분산 추적 모니터링 시스템으로서 signoz를 한 번 상세하게 알아보겠습니다.
이전 포스팅에서 signoz
에 대해 간단하게 알아봤는데요, 이번 포스팅에선 분산 추적 모니터링이라는 키워드에 초점을 맞춰서 signoz
를 알아보겠습니다.
앱 여러개 띄워보기
이전 포스팅의 코드에서 간단하게 다른 포트의 앱에게 HTTP 요청을 보낼 수 있는 API를 하나만 더 추가해 보겠습니다.
private final RestTemplate restTemplate;
@GetMapping("/call")
public String call(
@RequestParam int port,
@RequestParam(defaultValue = "test") String username) {
log.info("call localhost:{}...", port);
String url = "http://localhost:" + port + "/test?username=" + username;
return restTemplate.getForEntity(url, String.class)
.getBody();
}
위와 같은 API를 추가한 앱을 여러개 띄워 보겠습니다. (각각 8081~8084 포트를 가집니다.)
그럼 아래와 같이 service에 앱들이 열린 것을 확인할 수 있습니다.
앱 끼리 통신해보기
위에서 만들었던 call
API를 통해 앱끼리 통신을 해보겠습니다.
- 8081 -> 8082
- 8082 -> 8083
- 8082 -> 8084
- 8083 -> 8084
위와 같이 통신을 하고 나면 Service Map
메뉴를 통해 각 앱이 어디로 트래픽을 보내고 있는지 알 수 있습니다.
한 번 8082 -> 8083 API 통신에서 Error를 일으켜 보겠습니다.
Error를 발생시키고 나면 8083 앱에 문제가 생긴것으로 인식하고 이렇게 앱이 빨간색으로 바뀌게 됩니다.
추가로 8082 - 8083 사이의 선에 마우스를 올려보면 Error Rate가 50% 인 것을 확인할 수 있습니다.
여러 앱 사이의 exception 추적
지금처럼 8082 - 8083 사이의 통신에서 exception이 발생했을 때 보통은 양쪽 애플리케이션 로그를 모두 확인해야 합니다.
하지만 signoz는 분산 추적 모니터링을 지원하기 때문에 traceId
를 이용해 여러 앱 사이의 추적 로그를 확인할 수 있습니다.
위와 같이 excepton이 뜨면, 둘 중 하나를 눌러 see the error in trace graph
를 눌러봅니다.
그럼 아래에서 보듯이 8082 - 8083 사이의 모든 stack trace를 보여줍니다. 물론 양쪽 애플리케이션의 로그도 모두 함께 볼 수 있구요.
이런 signoz의 모니터링 능력은 MSA를 사용하거나 해서 애플리케이션간 연결 depth가 깊어지면 깊어질수록 진가를 발휘합니다.
어떻게 여러 앱들 사이에서 종합적인 모니터링이 가능할까?
trace와 span
분산 추적에서 추적에 해당하는 trace
는 사용자 요청의 시작과 끝을 의미합니다. 그리고 여러개의 span
으로 구성되는데, span
은 사용자 요청에서 작업을 완료하는 논리적 단위입니다.
span
에 대해서 알아야 할 몇 가지만 적어보자면,
-
Root Span:
trace
의 첫 번째span
을 나타내는 상위 스팬입니다. -
Child Span:
Child Span
(자식 스팬)은 부모 스팬에 의해 트리거되며 함수 호출, DB 호출, 다른 서비스에 대한 호출 등이 될 수 있습니다. -
Duration or Latency: 각 스팬이 프로세스를 완료하는 데 걸리는 시간입니다. 애플리케이션 성능을 분석하는 데 사용되는 주요 데이터 포인트입니다.
-
Causal relationship(인과 관계): 추적은 요청에 관련된 모든 스팬을 순차적 관계로 연관시킵니다.
우리가 Traces
섹션에서 봤던 각각의 bar가 하나의 span이고, 이를 통해 어디서 시간이 오래 걸렸는지 확인할 수 있습니다.
그럼 traceId는 어디서 만들어질까?
그럼 모든 애플리케이션을 지나가는 이 traceId는 어디서 만들어지고, 어떻게 전달될 수 있을까요?
서비스간의 통신에서 상대방이 받은 메시지중에 어떤 메시지가 내가 N번째로 보낸 메시지인지 어떻게 알 수 있을까요?
이는 아주 간단한데, 메시지를 보내는 쪽에서 traceId
에 해당하는 태그를 같이 보내주는 것입니다. (이를 위해 javaagent가 필요했습니다.)
TCP나 운영체제의 수준에서 메시지를 추적하려는 시도가 있었지만 프로토콜마다 별도로 구현해야 해 복잡도가 높고 성능이 좋지 않았다. 또한 메시지를 정확하게 추적하기 어려웠다.
traceId의 특징
수많은 endpoint에서 요청이 들어올 것이고, 마찬가지로 traceId
도 무수히 많이 생길 수 밖에 없습니다.
이를 위해 w3c
에선 분산 추적 표준을 지정해놨는데요, 그 중 traceId
필드 생성에 대한 고려 사항을 함께 살펴보겠습니다. (이는 권장사항으로 표준은 아닙니다.)
- uniqueness
- randomness
- traceId가 더 짧더라도 호환성을 유지해야함.
중복값이 최대한 적어야하고, 정보 보안을 위해 최대한 랜덤해야 한다고 되어 있습니다.
출처: https://www.w3.org/TR/trace-context/#considerations-for-trace-id-field-generation
마치며
여기까지 signoz에 대해서 알아봤는데요, 마냥 좋기만 할 줄 알았던 signoz
에도 큰 단점이 있었습니다.
바로 높은 카디널리티의 식별자에 대한 로그였는데요, 저희 팀은 사용자 문의가 들어오면 특정 요청에 대한 로그를 볼 일이 많은데, 그런 특정 요청에 대해서는 elasticSearch
보다 한참 느린 모습을 보여줬습니다.
집계 쿼리에 대해선 월등히 빠른 모습을 보여주고 있어서, 팀별로 정말 signoz가 필요한지 다시 한 번 확인하고 사용하는게 좋아보입니다.